package com.teatrace.commons.hibernate3.support;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.classic.Session;
import org.hibernate.context.CurrentSessionContext;
import org.hibernate.engine.SessionFactoryImplementor;

public class OpenSessionInViewCurrentSessionContext implements
		CurrentSessionContext {

	private static final Logger logger = Logger
			.getLogger(OpenSessionInViewCurrentSessionContext.class);
	
	private static final long serialVersionUID = 2792962482565232458L;

	private static OpenSessionInViewCurrentSessionContext __this;
	
	private SessionFactoryImplementor sessionFactory;

	private ThreadLocal<org.hibernate.Session> sessionLocal = new ThreadLocal<org.hibernate.Session>();

	public OpenSessionInViewCurrentSessionContext(
			SessionFactoryImplementor sessionFactory) {
		__this = this;
		this.sessionFactory = sessionFactory;
	}
	

	public Session currentSession() throws HibernateException {
		if (sessionLocal.get() != null) {
			return (Session)sessionLocal.get();
		}
		
		org.hibernate.Session session = sessionFactory.openSession();
		logger.debug(">>>>>	open Session");
		org.hibernate.Session proxy = (org.hibernate.Session) Proxy
				.newProxyInstance(session.getClass().getClassLoader(), session
						.getClass().getInterfaces(), new SessionProxy(session));
		sessionLocal.set(proxy);
		return (Session) proxy;
	}
	
	private static class SessionProxy implements InvocationHandler {

		private static final Logger logger = Logger
				.getLogger(SessionProxy.class);

		private static String[] interceptMethods = { "openSession", "close" };

		private org.hibernate.Session session;

		public SessionProxy(org.hibernate.Session session) {
			this.session = session;
		}

		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			if (method.getName().equals(interceptMethods[0])) {
				logger.debug(" Session open");
			} else if (method.getName().equals(interceptMethods[1])) {
				__this.sessionLocal.set(null);
				logger.debug("<<<<<	Session close");
			}
			return method.invoke(session, args);
		}

	}

}
